home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
ov143b.zip
/
OVDIR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-04
|
26KB
|
751 lines
/* 036 8-Jun-87 ovdir.c
Copyright (c) 1987 by Blue Sky Software. All rights reserved.
*/
#include <stdio.h>
#include "ov.h"
#include "overr.h"
#include "menu.h"
#include "direct.h"
#include "strmem.h"
#include "dosfile.h"
#define DCOLSIZ 15
#define DCOLS (SCREEN_COLS / DCOLSIZ)
#define dr2sr(r) (FIRST_NROW + (r - drbase))
#define dc2sc(c) ((c - dcbase) * DCOLSIZ)
#define TO_NONE 0
#define TO_SUBDIR 1
#define TO_SIBLING 2
#define TO_PARENT 3
#define TO_ROOT 4
char *strrchr(), *strupr();
struct search_block *nxtfile();
struct dir_ent {
struct dir_ent *subdir;
struct dir_ent *sibling;
struct dir_ent *parent;
struct dir_ent *prev_sib;
char name[13];
unsigned char row;
unsigned char col;
};
static last_drive = ' ';
static char dirpath[MAX_PATHLEN+6];
static int drbase, drend, dcbase, dcend;
static struct dir_ent *curdir, *logdir, *findir(), *dir_next();
static struct dir_ent root = { NULL, NULL, NULL, NULL, "", 0, 0 };
int dir_exit(), dir_login(), dir_mkdir(), dir_rmdir(), dir_new();
extern MENU top_file_menu[], *top_menu;
MENU top_dir_menu[] = {
{ "Login", "Login (switch) to the highlighted directory", dir_login, NULL },
{ "Mkdir", "Make a subdirectory of the highlighted directory", dir_mkdir, NULL },
{ "New", "Reread and redisplay directory tree", dir_new, NULL },
{ "Rmdir", "Remove (delete) the highlighted directory", dir_rmdir, NULL },
{ "Quit", "Return to file display", dir_exit, top_file_menu },
{ NULL, NULL, NULL, NULL }
};
extern WINDOW cw;
extern unsigned char dir_display, restricted;
char *strchr();
/******************************************************************************
** D T R E E **
*****************************************************************************/
dtree() { /* display / work with directory tree */
int drive;
dir_display = TRUE; /* dir tree is (will be) displayed */
restricted = TRUE; /* disable some file commands */
/* scan the current disk and create the internal directory tree if it
hasn't already been built or the user has changed disks */
if ((drive = current_drive()) != last_drive) { /* has the drive switched? */
if (root.subdir) { /* delete current tree */
del_dtree(root.subdir); /* if drive switch */
root.subdir = NULL;
}
last_drive = drive;
*dirpath = '\0'; /* scan_dir() starts at */
strncat(dirpath,cw.dirbuf,3); /* drives root dir */
strcpy(root.name,dirpath);
disp_msg(1,"Scanning disk"); /* takes awhile, tell user */
scan_dir(&root); /* build new dir tree */
dir_mark(); /* assign row/col's to ent's */
clr_msg(); /* done scanning */
drbase = dcbase = 0; /* assume dir */
drend = NAME_ROWS; /* will start */
dcend = DCOLS; /* at the root */
}
curdir = findir(); /* locate current dir in tree */
logdir = curdir; /* remember the logged dir */
/* now display the current portion of the dir tree */
adj_dir_dis(); /* make sure logged dir will show */
dir_distree(); /* let user see it */
top_menu = top_dir_menu; /* setup the dir menu as the main menu */
}
/******************************************************************************
D I R _ N E W
*****************************************************************************/
dir_new() { /* rescan the disk and redisplay the dir tree */
last_drive = ' '; /* simply force a rescan */
dtree(); /* and let dtree() do the work */
update_vol_stats(); /* in case its a new volume */
}
/******************************************************************************
** D I R _ E X I T **
*****************************************************************************/
dir_exit() { /* exit the dir display, return to file display */
dir_display = FALSE; /* dir tree will not be displayed */
restricted = FALSE; /* allow all file commands */
top_menu = top_file_menu; /* file menu is main again */
update_header(); /* always rewrite the entire screen */
refresh_screen(0); /* 'cause there may be > windows */
}
/******************************************************************************
** S C A N _ D I R **
*****************************************************************************/
scan_dir(dp) /* scan the specified dir tree for other directories */
struct dir_ent *dp;
{
int dplen;
int firsttime = TRUE;
struct search_block *sbp;
register struct dir_ent *ndp, *ldp = NULL;
/* build the pathname of the dir to scan */
dplen = strlen(dirpath); /* remember callers length */
if (strcmp(dp->name+2,"\\") != 0) { /* special case if root dir */
strcat(dirpath,dp->name); /* add name of dir to scan */
strcat(dirpath,"\\");
}
strcat(dirpath,"*.*"); /* add wildcard string */
/* scan all files in directory looking for subdirectories. When a
subdirectory is found, add it to the dir_ent tree. Note, the . and
.. directory entries are ignored. */
while (sbp = nxtfile(dirpath,0x16,&firsttime))
if (sbp->attrib & DIR && *sbp->fn != '.') {
/* found a subdir we want, build a struct dir_ent for it */
ndp = (struct dir_ent *) Malloc(sizeof(struct dir_ent));
strcpy(ndp->name,sbp->fn);
ndp->subdir = NULL;
ndp->sibling = NULL;
ndp->parent = dp;
ndp->prev_sib = ldp;
/* now link it to the dir_ent tree either as a subdir of the
parent (1st one only) or a sibling of the last one */
if (ldp)
ldp->sibling = ndp; /* not 1st, is a sibling */
else
dp->subdir = ndp; /* 1st one, subdir of parent */
ldp = ndp; /* new one is now the last one */
}
/* if any subdirectories were found, scan 'em. This isn't done
earlier so the file search isn't complicated by the directory
switches. */
if (ldp) { /* NULL if no sub's found */
dirpath[strlen(dirpath)-3] = '\0'; /* remove *.* for next level */
ldp = dp->subdir; /* start with the first one */
do {
scan_dir(ldp); /* call ourselves to scan this subtree */
} while (ldp = ldp->sibling); /* do all the subs found */
}
dirpath[dplen] = '\0'; /* restore dir pathname for caller */
}
/******************************************************************************
** D E L _ D T R E E **
*****************************************************************************/
del_dtree(dp) /* purge the current in memory dir tree structure */
register struct dir_ent *dp;
{
register struct dir_ent *ndp;
/* delete this subdirectory ENTRY and all sibling ENTRIES (not the
actual directories) */
do {
if (dp->subdir) /* if it has a subdir, make a recursive call */
del_dtree(dp->subdir); /* to delete the substructure */
ndp = dp->sibling; /* get address of any sibling */
free((char *)dp); /* free the dir_ent space itself */
} while (dp = ndp); /* do until no more siblings */
}
/******************************************************************************
D I R _ D I S T R E E
*****************************************************************************/
static int
dir_distree() { /* display the dir tree */
register int drow;
int i, ldrow = -1;
register struct dir_ent *dp = &root;
do {
drow = dp->row; /* speed things up a little */
/* if drow != ldrow, then this is the first entry on this display
row, clear the line to remove any old junk that might be there */
if (drow != ldrow && drow >= drbase && drow < drend) {
gotorc(dr2sr(drow),dc2sc(dcbase));
clr_eol();
ldrow = drow;
}
/* see if its necessary to put some spacer bars in from the previous
sibling. This will be necessary if the prev_sib had a desendent
with siblings because the siblings will occupy display lines
between this ent's prev_sib and where this ent goes. */
if (dp->prev_sib && (i = drow - dp->prev_sib->row - 1) > 0)
for (; i; i--)
if (dir_on_screen(drow-i,dp->col))
disp_char_at(0xb3,dr2sr(drow-i),dc2sc(dp->col));
/* only display a dir entry if it falls within the boundries, figure
out if this one does and display the name if so - the dir under
the pointer is highlighted, the logged dir is 'tagged' all others
are displayed 'normal' */
if (dir_on_screen(drow,dp->col))
disp_dir_name(dp,dp == curdir ? DIS_HIGH :
(dp == logdir ? DIS_TAGD : DIS_NORM));
} while (dp = dir_next(dp,&i,&i));
/* if we didn't reach the bottom of the display area, clear out the rest
of the lines to remove any garbage that might be there */
drow++; /* next would be display row */
if (drow - drbase < NAME_ROWS)
for (; drow - drbase < NAME_ROWS; drow++) {
gotorc(dr2sr(drow),dc2sc(dcbase));
clr_eol();
}
}
/******************************************************************************
** D I S P _ D I R _ N A M E **
*****************************************************************************/
disp_dir_name(dp,va) /* display a single dir name */
register struct dir_ent *dp;
int va;
{
gotorc(dr2sr(dp->row),dc2sc(dp->col)); /* move to display location */
/* display the leadin bar to the dir name, it depends on whether
this is the root, the 1st subdir, the last sibling, and if any
siblings follow */
if (dp->col) { /* root dir? */
if (dp->prev_sib == NULL) /* 1st subdir? */
disp_char((dp->sibling) ? 0xc2 : 0xc4); /* siblings follow? */
else
disp_char((dp->sibling) ? 0xc3 : 0xc0);
} else
disp_char(' '); /* root - no leadin */
if (va != DIS_NORM) /* setup highlight if needed */
setvattrib(va);
disp_char(' ');
disp_str(dp->name); /* display the name */
disp_char(' ');
/* draw bar to subdir or blank fill name */
disp_rep(dp->subdir ? 0xc4 : ' ',DCOLSIZ - strlen(dp->name) - 3);
if (va != DIS_NORM) /* restore normal attribute if changed */
setvattrib(DIS_NORM);
}
/*****************************************************************************
D I R _ M A R K
*****************************************************************************/
static int
dir_mark() { /* mark dir_ent's with logical row/column where they display */
register struct dir_ent *dp;
int nxtype, backup, drow, dcol;
dp = &root;
drow = dcol = 0;
/* scan the dir_ent tree in order */
while (dp = dir_next(dp,&nxtype,&backup)) {
if (nxtype) { /* NZ if dp is a sibling */
drow++; /* siblings go down a row */
dcol -= backup; /* and maybe back some */
} else
dcol++; /* sub dir's go over a column */
dp->row = drow; /* assign row/col to entry */
dp->col = dcol;
}
}
/******************************************************************************
D I R _ N E X T
******************************************************************************/
static struct dir_ent *
dir_next(dp,tp,bp) /* return address of next dir_ent */
register struct dir_ent *dp;
int *tp, *bp;
{
*bp = 0; /* assume we will not backup to parent */
if (dp->subdir) { /* subdir is next if there is one */
*tp = 0; /* tell caller its a sub dir */
return(dp->subdir);
}
*tp = 1; /* assume a sibling will be found */
if (dp->sibling) /* a sibling is next if there is one */
return(dp->sibling);
/* keep backing up until a parent is found with a sibling or root */
while ((dp = dp->parent) && dp != &root) {
(*bp)++; /* tell caller # levels backed up */
if (dp->sibling)
return(dp->sibling);
}
return(NULL); /* no more dir ents to be found */
}
/******************************************************************************
D I R _ M O V E
*****************************************************************************/
dir_move(move_cmd) /* move the directory pointer around */
int move_cmd;
{
int moved = TO_NONE;
int redisplayed = FALSE;
register struct dir_ent *last_dir, *cdp;
last_dir = cdp = curdir; /* remember where we are/were and fast ptr */
switch (move_cmd) {
case RIGHT:
if (cdp->subdir) {
cdp = cdp->subdir;
moved = TO_SUBDIR;
} else
if (cdp->sibling) {
cdp = cdp->sibling;
moved = TO_SIBLING;
}
/* stuff about parents goes here */
break;
case LEFT:
if (cdp->prev_sib) {
cdp = cdp->prev_sib;
moved = TO_SIBLING;
} else
if (cdp->parent) {
cdp = cdp->parent;
moved = TO_PARENT;
}
break;
case UP:
if (cdp->prev_sib) {
cdp = cdp->prev_sib;
moved = TO_SIBLING;
}
break;
case DOWN:
if (cdp->sibling) {
cdp = cdp->sibling;
moved = TO_SIBLING;
}
break;
case HOME:
cdp = &root;
moved = TO_ROOT;
break;
case GOPAR:
if (cdp->parent) {
cdp = cdp->parent;
moved = TO_PARENT;
}
break;
}
curdir = cdp; /* assign it */
/* adjust and redisplay the pathname as the user moves the dir pointer */
if (moved != TO_NONE)
update_dirpath(moved);
/* display a different section of dir tree if current isn't displayed */
if (adj_dir_dis()) { /* is adjustment needed? */
dir_distree(); /* display the tree */
redisplayed = TRUE; /* save a disp_dir_name() call */
}
/* deselect the last dir if the dir pointer moved and the last one
is still on the screen and the entire tree wasn't redisplayed */
if (!redisplayed && last_dir != curdir &&
dir_on_screen(last_dir->row,last_dir->col))
disp_dir_name(last_dir,last_dir == logdir ? DIS_TAGD : DIS_NORM);
/* select (highlight) a new dir entry if pointer moved and the tree
wasn't redisplayed */
if (last_dir != curdir && !redisplayed) {
disp_dir_name(curdir,DIS_HIGH);
}
}
/******************************************************************************
** D I R _ L O G I N **
*****************************************************************************/
dir_login() { /* login the dir selected by the dir pointer */
/* switch to selected dir, if can't switch, user may have changed
disks, force a scan of the disk for dirs */
if (switch_dir(dirpath) != 0) /* switch to the selected dir */
last_drive = ' ';
dir_exit(); /* exit the dir display mode */
}
/******************************************************************************
** D I R _ R M D I R **
*****************************************************************************/
dir_rmdir() { /* remove the dir selected by the dir pointer */
int moveto;
register struct dir_ent *cdp;
cdp = curdir; /* try to reduce code size */
/* don't even let user try to delete the root or current directories */
if (cdp->col == 0 || strcmp(dirpath,cw.dirbuf) == 0)
show_error(0,CANT_RMDIR,3,"You can't delete the ",(cdp->col == 0) ? "root" :
"current"," directory!");
/* use DOS to acutally remove the directory */
if (rmdir(dirpath) != 0)
show_error(SHOW_DOS,CANT_RMDIR,1,"Unable to remove dir: ");
/* Okay, the dir is gone, now remove it from the dir tree */
if (cdp->prev_sib) /* make prev sib -> */
cdp->prev_sib->sibling = cdp->sibling; /* next sib */
if (cdp->sibling) { /* next sib -> */
cdp->sibling->prev_sib = cdp->prev_sib; /* prev sib && */
if (cdp->parent->subdir == cdp) /* parent -> */
cdp->parent->subdir = cdp->sibling; /* next sib */
}
if (cdp->prev_sib == NULL && cdp->sibling == NULL) /* parent has no */
cdp->parent->subdir = NULL; /* more sub's */
/* when deleting a subdirectory, try to make a sibling the current dir,
if none, go back to parent */
if (cdp->sibling) {
curdir = cdp->sibling;
moveto = TO_SIBLING;
} else
if (cdp->prev_sib) {
curdir = cdp->prev_sib;
moveto = TO_SIBLING;
} else {
curdir = cdp->parent;
moveto = TO_PARENT;
}
update_vol_stats(); /* should be more free space now */
update_dirpath(moveto); /* show user what the dir pathname is */
free((char *)cdp); /* release mem used by the dir entry */
dir_mark(); /* reassign row/column values for remaining dir's */
adj_dir_dis(); /* make sure the current dir will display */
dir_distree(); /* redisplay updated dir tree */
}
/******************************************************************************
** D I R _ M K D I R **
*****************************************************************************/
dir_mkdir() { /* make a subdirectory in the selected dir */
int rc;
char *name, *dirend;
register struct dir_ent *ndp, *ldp;
/* ask user what to call the new directory */
name = strupr(prompt(NULL,"Enter the new subdirectory name: ",NULL,0,12));
if (strlen(name) == 0)
return;
/* update dirpath to include the users new name */
dirend = dirpath + strlen(dirpath); /* remember current dirpath end */
if (*(dirend-1) != '\\')
strcat(dirend,"\\");
strcat(dirend,name); /* add users dir name */
/* use DOS to acutally make the directory */
rc = mkdir(dirpath); /* create it */
*dirend = '\0'; /* fixup dirpath */
if (rc != 0)
show_error(SHOW_DOS,CANT_MKDIR,1,"Unable to make dir: ");
/* Okay, the dir is created, now make a dir_ent and add it to the dir tree */
ndp = (struct dir_ent *) Malloc(sizeof(struct dir_ent));
strcpy(ndp->name,name);
ndp->subdir = NULL;
ndp->sibling = NULL;
ndp->parent = curdir;
if (ldp = curdir->subdir) { /* any sibs to new dir? */
while (ldp->sibling) /* find end of sib list */
ldp = ldp->sibling;
ndp->prev_sib = ldp; /* new one is last */
ldp->sibling = ndp;
} else {
ndp->prev_sib = NULL; /* no sibs */
curdir->subdir = ndp; /* parent now has subdir */
}
update_vol_stats(); /* less free space now */
dir_mark(); /* assign new row/col values */
dir_distree(); /* redisplay dir tree */
}
/******************************************************************************
** U P D A T E _ D I R P A T H **
*****************************************************************************/
static int
update_dirpath(moved) /* update & redisplay dir path */
int moved;
{
char *cp;
switch (moved) {
case TO_SUBDIR: /* moved to a subdir */
if (curdir->col != 1) /* append a \ if parent wasn't root */
strcat(dirpath,"\\");
strcat(dirpath,curdir->name); /* append the subdirectory name */
break;
case TO_SIBLING: /* moved to a sibling */
*(strrchr(dirpath,'\\')+1) = '\0';
strcat(dirpath,curdir->name);
break;
case TO_PARENT: /* moved to parent */
cp = strrchr(dirpath,'\\');
if (curdir->col == 0)
++cp;
*cp = '\0';
break;
case TO_ROOT: /* moved to the root */
dirpath[3] = '\0';
break;
}
gotorc(VOL_ROW,PATH_COL+1);
out_str(dirpath,65,' ');
}
/*****************************************************************************
A D J _ D I R _ D I S
*****************************************************************************/
adj_dir_dis() { /* make sure current dir ent will be on screen */
register int r, c;
/* adjust bounds and redisplay dir tree if the current entry is not
displayed */
r = curdir->row; c = curdir->col; /* cutout a level of indirection */
if (!dir_on_screen(r,c)) {
if (r >= drend) /* current below display? */
drbase = r - NAME_ROWS + 1;
else
if (r < drbase) /* current above display? */
drbase = r;
if (c >= dcend) /* current right of display? */
dcbase = c - DCOLS + 1;
else
if (c < dcbase) /* current left of display? */
dcbase = c;
drend = drbase + NAME_ROWS; /* reset display end markers */
dcend = dcbase + DCOLS;
return(1); /* tell caller to redisplay */
}
return(0); /* no adjustment needed */
}
/*****************************************************************************
F I N D I R
*****************************************************************************/
static struct dir_ent *
findir() { /* find the current dir_ent */
register char *lcp;
char *cp = cw.dirbuf+3;
char dirname[MAX_NAMELEN+2];
register struct dir_ent *dp = &root;
*dirpath = '\0';
strncat(dirpath,cw.dirbuf,3); /* roots better be the same */
while (strcmp(dirpath,cw.dirbuf) != 0) { /* have we found it yet? */
/* haven't found it yet, go down another dir level, also do some
protective error checks, I don't feel real secure 'bout this yet */
if (dp == NULL || (dp = dp->subdir) == NULL || (lcp = cp) == NULL)
return(&root); /* shouldn't happen, but... */
if (cp = strchr(cp+1,'\\')) { /* isolate the next dir level */
*dirname = '\0'; /* in cw.dirbuf */
strncat(dirname,lcp,cp-lcp);
} else
strcpy(dirname,lcp); /* this must be the last level */
strcat(dirpath,dirname); /* add dir name to full path */
if (*(lcp = dirname) == '\\') /* 1st doesn't have leading \ */
lcp++; /* others do */
/* check all siblings at this level until we find it (or run out?) */
while (dp && strcmp(lcp,dp->name) != 0)
dp = dp->sibling;
}
return(dp); /* this should be the one */
}
/*****************************************************************************
D I R _ O N _ S C R E E N
*****************************************************************************/
static int
dir_on_screen(r,c) /* determine if dir name is displayed */
register int r, c;
{
return(r >= drbase && r < drend && c >= dcbase && c < dcend);
}